/*
 * @Description:
 * @Version: 1.0
 * @Autor: lzc
 * @Date: 2021-12-23 14:52:56
 * @LastEditors: lzc
 * @LastEditTime: 2021-12-29 12:47:57
 */

/* Constants that aren't configurable in menuconfig */
#include "http.h"

#define WEB_SERVER "restapi.amap.com"
#define WEB_PORT "80"
#define TAG "HTTP"
#define WEB_PATH "/v3/weather/weatherInfo?city=330400&key=18c2bce421cfffe5883f1700b8975934"

static const char *REQUEST = "GET " WEB_PATH " HTTP/1.0\r\n"
                             "Host: " WEB_SERVER ":" WEB_PORT "\r\n"
                             "User-Agent: esp-idf/1.0 esp32\r\n"
                             "\r\n";

char recv_buf_temp[2048] = {0};
char json_buf_temp[1025] = {0};

HTTP_weather_data_t HTTP_weather_data;

int MyStrstr(char *str, char *substr);
void Get_http_Weather_body(char *str, char *result);
void Parse_http_weather_json(char *json);
void Get_System_Information(void);

void http_get_task(void *pvParameters)
{
    const struct addrinfo hints = {
        .ai_family = AF_INET,
        .ai_socktype = SOCK_STREAM,
    };
    struct addrinfo *res;
    struct in_addr *addr;
    int s, r;
    // char recv_buf[64];

    while (1)
    {
        int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);

        if (err != 0 || res == NULL)
        {
            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }

        /* Code to print the resolved IP.

           Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
        addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
        ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));

        s = socket(res->ai_family, res->ai_socktype, 0);
        if (s < 0)
        {
            ESP_LOGE(TAG, "... Failed to allocate socket.");
            freeaddrinfo(res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... allocated socket");

        if (connect(s, res->ai_addr, res->ai_addrlen) != 0)
        {
            ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
            close(s);
            freeaddrinfo(res);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }

        ESP_LOGI(TAG, "... connected");
        freeaddrinfo(res);

        if (write(s, REQUEST, strlen(REQUEST)) < 0)
        {
            ESP_LOGE(TAG, "... socket send failed");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... socket send success");

        struct timeval receiving_timeout;
        receiving_timeout.tv_sec = 5;
        receiving_timeout.tv_usec = 0;
        if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout, sizeof(receiving_timeout)) < 0)
        {
            ESP_LOGE(TAG, "... failed to set socket receiving timeout");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... set socket receiving timeout success");
        /* Read HTTP response */
        ESP_LOGI(TAG, "... Get Temp buffer!!!!!!!!!!...");

        bzero(recv_buf_temp, sizeof(recv_buf_temp));
        do
        {
            r = read(s, recv_buf_temp, sizeof(recv_buf_temp) - 1);
            for (int i = 0; i < r; i++)
            {
                putchar(recv_buf_temp[i]);
            }
        } while (r > 0);
        Get_http_Weather_body(recv_buf_temp, json_buf_temp);
        Parse_http_weather_json(json_buf_temp);

        ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d.", r, errno);
        close(s);
        // 两分钟获取一次
        for (int countdown = 120; countdown >= 0; countdown--)
        {
            ESP_LOGD(TAG, "%d... ", countdown);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
        ESP_LOGI(TAG, "Starting again!");
    }
}

void Parse_http_weather_json(char *json)
{
    cJSON *pJsonRoot = cJSON_Parse(json);
    //如果是否json格式数据
    if (pJsonRoot != NULL)
    {
        cJSON *pArryInfo = cJSON_GetObjectItem(pJsonRoot, "lives"); // 解析字段数组内容
        cJSON *pInfoItem = NULL;
        cJSON *pInfoObj = NULL;
        char strWeather[20] = {0};
        char strCity[20] = {0};
        char strTemperature[20] = {0};
        char strWinddirection[20] = {0};
        char strHumidity[20] = {0};
        char strReporttime[20] = {0};

        if (!pArryInfo)
            return; // 判断字段是否json格式
        else
        {
            int arryLength = cJSON_GetArraySize(pArryInfo); // 获取数组长度
            int i;
            for (i = 0; i < arryLength; i++)
            {
                pInfoItem = cJSON_GetArrayItem(pArryInfo, i); // 获取数组中JSON对象
                if (NULL != pInfoItem)
                {
                    // NOTE: 解析JSON数据 ：weather 字段
                    pInfoObj = cJSON_GetObjectItem(pInfoItem, "weather"); // 解析weather字段字符串内容
                    if (pInfoObj)
                    {
                        strcpy(strWeather, pInfoObj->valuestring); // 拷贝内容到字符串数组
                        ESP_LOGI(TAG, "strWeather = %s \n", strWeather);
                    }

                    // NOTE: 解析JSON数据 ：city 字段
                    pInfoObj = cJSON_GetObjectItem(pInfoItem, "city"); // 解析city字段字符串内容
                    if (pInfoObj)
                    {
                        strcpy(strCity, pInfoObj->valuestring); // 拷贝内容到字符串数组
                        ESP_LOGI(TAG, "strCity = %s \n", strCity);
                    }

                    // NOTE: 解析JSON数据 temperature 字段
                    pInfoObj = cJSON_GetObjectItem(pInfoItem, "temperature"); // 解析temperature字段字符串内容
                    if (pInfoObj)
                    {
                        strcpy(strTemperature, pInfoObj->valuestring); // 拷贝内容到字符串数组
                        ESP_LOGI(TAG, "strTemperature = %s \n", strTemperature);
                    }

                    // NOTE: 解析JSON数据 ：humidity 字段
                    pInfoObj = cJSON_GetObjectItem(pInfoItem, "humidity"); // 解析humidity字段字符串内容
                    if (pInfoObj)
                    {
                        strcpy(strHumidity, pInfoObj->valuestring); // 拷贝内容到字符串数组
                        ESP_LOGI(TAG, "strHumidity = %s \n", strHumidity);
                    }

                    // NOTE: 解析JSON数据 winddirection 字段
                    pInfoObj = cJSON_GetObjectItem(pInfoItem, "winddirection"); // 解析winddirection字段字符串内容
                    if (pInfoObj)
                    {
                        strcpy(strWinddirection, pInfoObj->valuestring); // 拷贝内容到字符串数组
                        ESP_LOGI(TAG, "strWinddirection = %s \n", strWinddirection);
                    }

                    // NOTE: 解析JSON数据 reporttime 字段
                    pInfoObj = cJSON_GetObjectItem(pInfoItem, "reporttime"); // 解析reporttime字段字符串内容
                    if (pInfoObj)
                    {
                        strcpy(strReporttime, pInfoObj->valuestring); // 拷贝内容到字符串数组
                        ESP_LOGI(TAG, "strReporttime = %s \n", strReporttime);
                    }
                }
            }
        }

        memcpy(HTTP_weather_data.City, strCity, sizeof(strCity));

        memcpy(HTTP_weather_data.Temperature, strTemperature, sizeof(strTemperature));
        memcpy(HTTP_weather_data.Weather, strWeather, sizeof(strWeather));
        memcpy(HTTP_weather_data.Wind_Direction, strWinddirection, sizeof(strWinddirection));
        memcpy(HTTP_weather_data.Humidity, strHumidity, sizeof(strHumidity));
        memcpy(HTTP_weather_data.Update_Time, strReporttime, sizeof(strReporttime));

        strcat(HTTP_weather_data.Temperature, " \uF2C7"); //温度计标志的显示
        strcat(HTTP_weather_data.Humidity, " \uF043");    //湿度标志的显示
    }
    cJSON_Delete(pJsonRoot); // 递归删除
    Get_System_Information();
}

void Get_http_Weather_body(char *str, char *result)
{
    int Content_length_pos = 0;
    int Json_Start_pos = 0;
    int Connection_pos = 0;
    int pos_len = 0;
    int body_length = 0;

    Content_length_pos = MyStrstr(str, "Content-Length");
    Json_Start_pos = MyStrstr(str, "{");
    Connection_pos = MyStrstr(str, "Connection");
    pos_len = Connection_pos - sizeof("Content-Length: \n") - Content_length_pos;
    for (int i = 0; i < (pos_len); i++)
    {
        ESP_LOGD(TAG, "recv_buf_temp[%d] = %c \n", Content_length_pos + sizeof("Content-Length: ") + i - 1,
                 str[Content_length_pos + sizeof("Content-Length: ") + i - 1]);
        body_length += (str[Content_length_pos + sizeof("Content-Length: ") + i - 1] - '0') * pow(10, (pos_len - i - 1));
    }
    ESP_LOGD(TAG, "body_length = %d \n", body_length);
    ESP_LOGD(TAG, "Json_Start_pos = %d \n", Json_Start_pos);
    memcpy(result, str + Json_Start_pos, body_length);
    ESP_LOGI(TAG, "Json_Data = %s \n", result);
}

int MyStrstr(char *str, char *substr)
{
    int num = 0;
    while (*str != '\0')
    {
        if (*str != *substr)
        {
            str++;
            num++;
            continue;
        }

        //创建临时指针
        char *tmpstr = str;
        char *tmpsubstr = substr;

        while (*tmpsubstr != '\0')
        {
            if (*tmpstr != *tmpsubstr)
            {
                //匹配失败
                str++;
                num++;
                break;
            }
            tmpstr++;
            tmpsubstr++;
        }
        if (*tmpsubstr == '\0') //匹配成功
        {
            return num;
        }
    }
    return -1;
}

char *S_trtok(char *scr, char sign, int index)
{
    char *tar = (char *)malloc(100); //开辟堆空间
    int i = 0;
    int flag = 0;
    int startpos = 0;
    int endpos = 0;
    while (scr[i] != '\0')
    {
        if (scr[i] == sign)
        {
            flag++;
            if (flag == index - 1)
            {
                startpos = i + 1;
            }
            if (flag == index)
            {
                endpos = i;
            }
        }
        i++;
    }
    if (endpos == 0) //用于查找最后一个，此时字符串末尾的'\0'可以当做','
    {
        endpos = i;
    }
    strncpy(tar, scr + startpos, endpos - startpos);
    return tar;
}

void Get_System_Information(void)
{
    printf("\n\n-------------------------------- Get Systrm Info------------------------------------------\n");
    //获取IDF版本
    printf("     SDK version:%s\n", esp_get_idf_version());
    //获取芯片可用内存
    printf("     esp_get_free_heap_size : %d  \n", esp_get_free_heap_size());
    //获取芯片可用内存
    printf("     esp_get_free_internal_heap_size : %d  \n", esp_get_free_internal_heap_size());
    //获取从未使用过的最小内存
    printf("     esp_get_minimum_free_heap_size : %d  \n", esp_get_minimum_free_heap_size());
    //获取mac地址（station模式）
    uint8_t mac[6];
    esp_read_mac(mac, ESP_MAC_WIFI_STA);
    printf("     esp_read_mac : %02x:%02x:%02x:%02x:%02x:%02x \n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    printf("\n\n-----------------------------------------------------------------------------------------\n");
}
